#pragma once
#include<iostream>
#include<fstream>
#include<ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include"../../Server/TcpServer/TcpServer.hpp"
#include"./Status.hpp"
#include"./Mime.hpp"

//http协议的工具接口
class Util
{
public:
    //读文件内容,将内容放到string中
    static bool ReadFile(const std::string& filename, std::string& ret)
    {
        //打开文件
        std::ifstream file(filename, std::ios::binary);
        if(file.is_open() == false)
        {
            ERR_LOG("file %s open fail", filename.c_str());
            return false;
        }
        //获取文件的大小
        file.seekg(0, file.end);
        int size = file.tellg();
        file.seekg(0, file.beg);
        ret.resize(size);
        //读文件
        file.read(&ret[0], size);
        if(file.good() == false)
        {
            ERR_LOG("file %s read fail", filename.c_str());
            file.close();
            return false;
        }
        file.close();
        return true;
    }

    //写文件,将string的内容写到文件中
    static bool WriteFile(const std::string filename, const std::string& data)
    {
        //打开文件
        std::ofstream file(filename, std::ios::binary|std::ios::trunc);
        if(file.is_open() == false)
        {
            ERR_LOG("file %s open fail", filename.c_str());
            return false;
        }
        //写数据
        file.write(data.c_str(), data.size());
        if(file.good() == false)
        {
            ERR_LOG("file %s write fail", filename.c_str());
            file.close();
            return false;
        }
        file.close();
        return true;
    }

    //URL编码:
    //编码格式：将特殊字符的ascii值，转换为两个16进制字符，前缀%   C++ -> C%2B%2B
    //不编码的特殊字符： RFC3986文档规定 . - _ ~ 字母，数字属于绝对不编码字符
    //RFC3986文档规定，编码格式 %HH 
    //W3C标准中规定，查询字符串中的空格，需要编码为+， 解码则是+转空格
    static std::string URLEncode(std::string url, bool if_space_encode)
    {
        std::string ret;
        for(int i = 0; i < url.size(); i++)
        {
            if(url[i] == '.'||url[i] == '-'||url[i] == '_'||url[i] == '~')
            {
                ret += url[i];
            }
            else if(url[i] == ' ' && if_space_encode == true)
            {
                ret += '+';
            }
            else if(isalnum(url[i]) != 0)
            {
                ret += url[i];
            }
            else
            {
                //进行16进制编码
                char arr[4] = {0};
                snprintf(arr, 4, "%%%02X", url[i]);
                ret += arr;
            }
        }
        return ret;
    }

    //URL解码
        //16进制转换
    static int HEXTODEC(char c)
    {
        if(c >= '0' && c <= '9')
        {
            return c - '0';
        }
        else if(c >= 'a' && c <= 'f')
        {
            return c - 'a' + 10;
        }
        else if(c >= 'A' && c <= 'F')
        {
            return c - 'A' + 10;
        }
    }
    static std::string URLDecode(std::string url, bool if_plus_decode)
    {
        std::string ret;
        for(int i = 0; i < url.size(); i++)
        {
            if(url[i] == '%' && i+2 < url.size())
            {
                int n = HEXTODEC(url[i+1]) * 16 + HEXTODEC(url[i+2]);
                ret += n;
                i += 2;
            }
            else if(url[i] == '+' && if_plus_decode == true)
            {
                ret += ' ';
            }
            else
            {
                ret += url[i];
            }
        }
        return ret;
    }

    //获取状态码的信息
    static std::string StatusMessage(int status)
    {
        auto it = _status.find(status);
        if(it != _status.end())
        {
            return it->second;
        }
        else
        {
            return "Unknown";
        }
    }

    //根据文件后缀获取文件mime
    static std::string FileMime(std::string filename)
    {
        int pos = filename.find_last_of('.');
        if(pos != std::string::npos)
        {
            std::string str = filename.substr(pos);
            auto it = _mime.find(str);
            if(it != _mime.end())
            {
                return it->second;
            }
            else
            {
                return "application/octet-stream";
            }
        }
        return "application/octet-stream";
    }

    //判断文件是否是一个目录
    static bool IsDirectory(const std::string& filename)
    {
        struct stat s;
        int ret = stat(filename.c_str(), &s);
        if(ret < 0)
        {
            return false;
        }
        return S_ISDIR(s.st_mode);
    }

    //判断文件是否是一个普通文件
    static bool IsRegular(const std::string& filename)
    {
        struct stat s;
        int ret = stat(filename.c_str(), &s);
        if(ret < 0)
        {
            return false;
        }
        return S_ISREG(s.st_mode);
    }

    //判断文件路径是否合法
        //字符串分割
    static void split(std::string filename, const std::string &sep, std::vector<std::string>& array)
    {
        //如果路径为空或者只有一个/,直接返回
        if(filename.size() == 1 || filename.size() == 0)
            return;

        //否则直接从第二个元素开始查找
        int pos = 1;
        while(pos < filename.size())
        {
            int index = filename.find(sep, pos);
            if(index != std::string::npos)
            {
                std::string str = filename.substr(pos, index-pos);
                array.push_back(str);
                //从/的后一个数据开始读
                pos = index+1;
            }
            else
            {
                //没找到就看最后一个/后面有没有数据
                if(pos < filename.size()-1)
                {
                    std::string str = filename.substr(pos);
                    array.push_back(str);
                }
                return;
            }
        }
    }
    static bool ValidPath(const std::string& path)
    {
        std::vector<std::string> arr;
        split(path, "/", arr);
        //访问.. level就--， 访问其他 level就++，如果level小于0就是无效路径
        int level = 0;
        for(auto& e:arr)
        {
            if(e == "..")
            {
                level--;
                if(level < 0) return false;
            }
            else
            {
                level++;
            }
        }
        return true;
    }
};

